/******************** (C) COPYRIGHT 2018 merafour ********************
* Author             : 冷月追风@merafour.blog.163.com
* Version            : V1.0.0
* Date               : 8/1/2019
* Description        : 同步信号定义.
********************************************************************************
* merafour.blog.163.com
* merafour@163.com
* github.com/Merafour
*******************************************************************************/

#ifndef QIMSGSYNC_H
#define QIMSGSYNC_H

#include <QObject>
#include <QThread>
#include "qimsgport.h"

class QiMSGSync : public QObject
{
    Q_OBJECT
public:
    //explicit QiMSGSync(QObject *parent = nullptr);
    explicit QiMSGSync(QObject *parent, QiMSGPort &_port) : QObject(parent), _Port(_port)
    {
        ;
    }

    enum Code
    {
        // response codes
        NOP = 0x00,
        OK = 0x10,
        FAILED = 0x11,
        INSYNC = 0x12,
        INVALID = 0x13,//	# rev3+

        // protocol commands
        EOC = 0x50,
        GET_SYNC = 0x21,
        GET_DEVICE = 0x22,	// returns DEVICE_ID and FREQ bytes
        CHIP_ERASE = 0x23,
        CHIP_VERIFY = 0x24,//# rev2 only
        PROG_MULTI = 0x27,
        READ_MULTI = 0x28,//# rev2 only
        GET_CRC = 0x29,//	# rev3+
        GET_OTP = 0x2a, // read a byte from OTP at the given address
        GET_SN = 0x2b,    // read a word from UDID area ( Serial)  at the given address
        GET_CHIP = 0x2c, // read chip version (MCU IDCODE)
        PROTO_SET_DELAY	= 0x2d, // set minimum boot delay
        REBOOT = 0x30,
        STANDBY = 0x32,
        GET_ID = 0x33,
        ENCRYPT = 0x34,
        B2_SYNC = 0x35,
        GET_ID_TEA = 0x36,
        ENCRYPT_TEA = 0x37,
        GET_KEY = 0x38, // 交换私钥
        GET_ID_TEAD = 0x39, // 动态密钥
        PARAMW = 0x3A,      // 写参数
        PARAMR = 0x3B,      // 读参数
        STREAM = 0x3C,      // 数据流
    };
    enum Info {
        BL_REV = 1,//	# bootloader protocol revision
        BOARD_ID = 2,//	# board type
        BOARD_REV = 3,//	# board revision
        FLASH_SIZE = 4,//	# max firmware size in bytes
        VEC_AREA = 5,
        PARAM1 = 6,
        PARAM2 = 7,
        PARAM3 = 8,
        PARAM4 = 9,
        PARAM5 = 10,
        PARAM6 = 11,
        PARAM7 = 12,
    };
    enum SingalCode
    {
        // response codes
        DOWN  = 0x0180,
        CRC   = 0x0181,
        SCAN  = 0x0182,
        TIME  = 0x0183,
        ERR   = 0x0184,
        PULL  = 0x0185,
        MSG   = 0x0186,
        REPO  = 0x0187,  // Reported
        PARAM = 0x0188,  // Parameter
    };
    int __scan(void)
    {
//        uint8_t buf[2];
//        buf[0] = Code::GET_SYNC;
//        buf[1] = Code::EOC;
        _Port.clear();
        QThread::msleep(1);
        //__send(buf, 2);
        __send(cmd_sync, sizeof (cmd_sync));
        _Port.watting_data(10);
        uint8_t insync = __recv();
        uint8_t ok = __recv();
        //return __getSync();
        if((static_cast<uint8_t>(Code::INSYNC) == insync) && (static_cast<uint8_t>(Code::OK) == ok)) return 0;
        return -1;
    }
    int __stream(void)
    {
        _Port.clear();
        QThread::msleep(1);
        __send(cmd_stream, sizeof (cmd_stream));
        _Port.watting_data(10);
        __getSync();
    }
    void __send(const uint8_t buf[], const uint32_t len)
    {
        _Port.write(reinterpret_cast<const char *>(buf), len);
    }
    int __sync(void)
    {
//        uint8_t buf[2];
//        buf[0] = Code::GET_SYNC;
//        //buf[0] = Code::GET_CRC;
//        buf[1] = Code::EOC;
        _Port.clear();
        QThread::msleep(1);
        __send(cmd_sync, sizeof (cmd_sync));
        _Port.watting_data(100);
        return __getSync();
    }
    int __getSync(void);
    int __recv(uint8_t buf[], const int count = 2)
    {
        return _Port.read(buf, count);
    }
    uint8_t __recv(void)
    {
        return _Port.read();
    }
    int __recv_int(void);
    int __getInfo(Info param)
    {
        uint8_t buf[3];
        buf[0] = Code::GET_DEVICE;
        buf[1] = param;
        buf[2] = Code::EOC;
        _Port.clear();
        QThread::msleep(1);
        __send(buf, 3);
        //QThread::msleep(1500);
        //_Port.watting_data(1000);
        int info = __recv_int();
        __getSync();
        qDebug("info:%0X %d", info, info);
        return info;
    }
    int __readParam(Info param)
    {
        uint8_t buf[3];
        buf[0] = Code::PARAMR;
        buf[1] = param;
        buf[2] = Code::EOC;
        _Port.clear();
        QThread::msleep(1);
        __send(buf, 3);
        _Port.watting_data(10);
        int info = __recv_int();
        __getSync();
        qDebug("param:%0X %d", info, info);
        return info;
    }
    void __writeParam(Info param, const uint32_t value)
    {
        uint8_t buf[7];
        buf[0] = Code::PARAMW;
        buf[1] = param;
        buf[2] = (value)&0xFF;
        buf[3] = (value>>8)&0xFF;
        buf[4] = (value>>16)&0xFF;
        buf[5] = (value>>24)&0xFF;
        buf[6] = Code::EOC;
        _Port.clear();
        QThread::msleep(1);
        __send(buf, sizeof(buf));
        __getSync();
    }
    void __reboot(void)
    {
//        uint8_t buf[2];
//        buf[0] = Code::REBOOT;
//        buf[1] = Code::EOC;
        __send(cmd_reboot, sizeof (cmd_reboot));
        _Port.flush();
        _Port.watting_data(300); // 300ms
        __getSync();
    }
    int identify(void)
    {
        if(0!=__sync())
        {
            return -1;
        }
//        QThread::msleep(300);
//        _Port.flush();
//        _Port.clear();
        bl_rev=__getInfo(Info::BL_REV);
        bl_rev=__getInfo(Info::BL_REV);
    //     if ((bl_rev < (int)BL_REV_MIN) || (bl_rev > (int)BL_REV_MAX))
    //     {
    //         throw new Exception("Bootloader protocol mismatch");
    //     }

         board_type = __getInfo(Info::BOARD_ID);
         board_rev = __getInfo(Info::BOARD_REV);
         fw_maxsize = __getInfo(Info::FLASH_SIZE);
         return 0;
    }

    int board_type;
    int board_rev;
    int fw_maxsize;
    int bl_rev;
signals:
    void sig_progress_update(const QString &titel, int value);

public slots:

protected:
    static const uint8_t cmd_reboot[2];
    static const uint8_t cmd_sync[2];
    static const uint8_t cmd_stream[2];
    QiMSGPort &_Port;
private:

};

// 定义数据传递的接口
//class QiMSGdata
//{
//public:
//    QiMSGdata()
//    {
//        ;
//    }
//}

#endif // QIMSGSYNC_H
